import 'dart:math';

import 'package:flutter/material.dart';

class SpecialShapesPaint extends StatelessWidget {
  const SpecialShapesPaint({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: SpecialShapesPainter(),
    );
  }
}

class SpecialShapesPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawColor(Color(0xFFF1F1F1), BlendMode.color);
    var center = size / 2;
    var paint = Paint()..color = Color(0xFF2080E5);
    paint.strokeWidth = 2.0;
    // 空心绘制
    //paint.style = PaintingStyle.stroke;
    List<Color> colors = [
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFF10AFA0),
      Color(0xFF8080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFF10AFA0),
      Color(0xFF8080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFF10AFA0),
      Color(0xFF8080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
      Color(0xFF10AFA0),
      Color(0xFF8080E5),
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080E5),
    ];
    int number = 24;
    for (int i = 0; i < number; ++i) {
      drawEquilateralTriangle(
        canvas,
        color: colors[i],
        startVertex: Offset(center.width, center.height),
        length: 120,
        startAngle: i * 2 * pi / number,
        clockwise: true,
        filled: true,
      );
    }

    drawRainbow(
      canvas,
      startPoint: Offset(center.width - 150, 100),
      width: 300,
    );
    for (int i = 0; i < 5; ++i) {
      drawStar(
        canvas,
        center: Offset(
          center.width - (2 - i) * 10,
          center.height + 200,
        ),
        length: 10,
        color: Colors.orange[300]!,
        filled: i < 4,
      );
    }
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) {
    return false;
  }

  void drawStar(
    Canvas canvas, {
    required Offset center,
    required double length,
    required Color color,
    bool filled = true,
  }) {
    assert(length > 0);
    List<Offset> starVertexes =
        ShapesUtil.getStarVertexes(Offset(center.dx, center.dy), length);
    Path starPath = Path();
    starPath.moveTo(starVertexes[0].dx, starVertexes[0].dy);
    for (int i = 1; i < starVertexes.length; i++) {
      starPath.lineTo(starVertexes[i].dx, starVertexes[i].dy);
    }
    starPath.close();
    var paint = Paint();
    paint.color = color;

    if (!filled) {
      paint.style = PaintingStyle.stroke;
    }
    canvas.drawPath(starPath, paint);
  }

  void drawRainbow(
    Canvas canvas, {
    required Offset startPoint,
    required double width,
  }) {
    assert(width > 0);
    var paint = Paint();
    double rowHeight = 12;
    paint.strokeWidth = rowHeight / 2;
    List<Color> colors = [
      Color(0xFFE05100),
      Color(0xFFF0A060),
      Color(0xFFE0E000),
      Color(0xFF10F020),
      Color(0xFF2080F5),
      Color(0xFF104FF0),
      Color(0xFFA040E5),
    ];
    paint.style = PaintingStyle.stroke;
    for (var i = 0; i < 7; i++) {
      double innerWidth = width - i * rowHeight;
      Path path1 = Path();
      Rect rect1 = Rect.fromLTWH(startPoint.dx + (width - innerWidth) / 2,
          startPoint.dy + (width - innerWidth) / 2, innerWidth, innerWidth);
      path1.arcTo(rect1, -pi / 6, -2 * pi / 3, true);
      paint.color = colors[i];
      canvas.drawPath(path1, paint);
    }
  }

  // 绘制等边三角形
  void drawEquilateralTriangle(
    Canvas canvas, {
    required Color color,
    required Offset startVertex,
    required double length,
    double startAngle = 0,
    clockwise = true,
    filled = true,
  }) {
    assert(length > 0);
    Path trianglePath = Path();
    List<Offset> vertexes = ShapesUtil.getEquilateralTriangleVertexes(
      startVertex,
      length,
      clockwise: clockwise,
      startAngle: startAngle,
    );
    trianglePath.moveTo(vertexes[0].dx, vertexes[0].dy);
    for (int i = 1; i < vertexes.length; i++) {
      trianglePath.lineTo(vertexes[i].dx, vertexes[i].dy);
    }
    trianglePath.close();
    Paint paint = Paint();
    paint.color = color;
    if (!filled) {
      paint.style = PaintingStyle.stroke;
    }
    canvas.drawPath(trianglePath, paint);
  }
}

class ShapesUtil {
  /// 获取等边三角形的3个顶点，以顶点偏移 startAngle 取第一条边（围绕第一个顶点变化）
  static List<Offset> getEquilateralTriangleVertexes(
      Offset startVertex, double length,
      {double startAngle = 0, bool clockwise = true}) {
    double point2X, point2Y, point3X, point3Y;
    point2X = startVertex.dx + length * cos(startAngle);
    point2Y = startVertex.dy - length * sin(startAngle);
    if (clockwise) {
      point3X = startVertex.dx + length * cos(pi / 3 + startAngle);
      point3Y = startVertex.dy - length * sin(pi / 3 + startAngle);
    } else {
      point3X = startVertex.dx + length * cos(pi / 3 - startAngle);
      point3Y = startVertex.dy + length * sin(pi / 3 - startAngle);
    }

    return [startVertex, Offset(point2X, point2Y), Offset(point3X, point3Y)];
  }

  // 围绕等边三角形中心旋转startAngle（中心点不变）
  static List<Offset> getEquilateralTriangleVertexesRotateByCenter(
      Offset center, double length,
      {double startAngle = 0, bool clockwise = true}) {
    assert(length > 0);
    // 外接圆半径计算
    double radius = length / 2 / cos(30 / 180 * pi);

    List<Offset> vertexes = [];
    // 起始点对齐中心 x 轴的坐标
    Offset centerVertex = Offset(center.dx, center.dy - radius);
    // 实际偏移 startAngle 后的起始点坐标
    Offset startVertex = Offset(
      center.dx +
          (centerVertex.dx - center.dx) * cos(-startAngle) -
          (centerVertex.dy - center.dy) * sin(-startAngle),
      center.dy +
          (centerVertex.dy - center.dy) * cos(-startAngle) +
          (centerVertex.dx - center.dx) * sin(-startAngle),
    );

    vertexes.add(startVertex);
    // 计算方式为以第一个顶点围绕中心点坐标旋转得到
    // 方法参考：https://www.cnblogs.com/fangsmile/p/8622421.html
    double rotateAngle = clockwise ? 120 / 180 * pi : -120 / 180 * pi;
    for (int i = 1; i < 3; ++i) {
      vertexes.add(Offset(
        center.dx +
            (startVertex.dx - center.dx) * cos(-i * rotateAngle) -
            (startVertex.dy - center.dy) * sin(-i * rotateAngle),
        center.dy +
            (startVertex.dy - center.dy) * cos(-i * rotateAngle) +
            (startVertex.dx - center.dx) * sin(-i * rotateAngle),
      ));
    }

    return vertexes;
  }

  /// 获取五角星10个顶点
  /// center：五角星中心点
  /// length：五角星边长
  /// 计算方式：以五角星的五个锐角顶点外接圆方式计算
  static List<Offset> getStarVertexes(Offset center, double length) {
    assert(length > 0);
    // 外接圆半径计算（五角星锐角为36度）
    double radius = length / 2 / cos(18 / 180 * pi);
    const double innerBiasAngle = 36 / 180 * pi;
    // 内部顶点的半径
    double innerRadius = radius /
        (cos(innerBiasAngle) + sin(innerBiasAngle) / sin(innerBiasAngle / 2));
    List<Offset> vertexes = [];
    Offset outerStartVertex = Offset(center.dx, center.dy - radius);
    Offset innerStartVertex = Offset(
      center.dx - innerRadius * sin(innerBiasAngle),
      center.dy - innerRadius * cos(innerBiasAngle),
    );
    vertexes.add(outerStartVertex);
    vertexes.add(innerStartVertex);
    // 计算方式为以第一个顶点围绕五角星中心点坐标旋转得到
    // 方法参考：https://www.cnblogs.com/fangsmile/p/8622421.html
    const double rotateAngle = 72 / 180 * pi;
    for (int i = 1; i < 5; ++i) {
      vertexes.add(Offset(
        center.dx +
            (outerStartVertex.dx - center.dx) * cos(-i * rotateAngle) -
            (outerStartVertex.dy - center.dy) * sin(-i * rotateAngle),
        center.dy +
            (outerStartVertex.dy - center.dy) * cos(-i * rotateAngle) +
            (outerStartVertex.dx - center.dx) * sin(-i * rotateAngle),
      ));
      vertexes.add(Offset(
        center.dx +
            (innerStartVertex.dx - center.dx) * cos(-i * rotateAngle) -
            (innerStartVertex.dy - center.dy) * sin(-i * rotateAngle),
        center.dy +
            (innerStartVertex.dy - center.dy) * cos(-i * rotateAngle) +
            (innerStartVertex.dx - center.dx) * sin(-i * rotateAngle),
      ));
    }

    return vertexes;
  }
}
